
/**
  * @file win_thread_impl.h
  * < windows thread warpped >
  *
  * Copyright (c) by <lid/>
  * @author jingwei.guan@hotmail.com
  * modify history:
  * date     version     author     content
  * 1/8/2011  0.0.1       lid       thread have to provide create, start, end,
									run_delegate, done_delegate, notice_container_delegate function for container policy
 */


#define WindowsThread_Template_Params    Make_Params1(WindowsThread_Num_Args, class T) // class T0, class T1, class T2, ...
#define WindowsThread_Template_Args      Make_Params1(WindowsThread_Num_Args, T) // T0, T1, T2, ...
#define WindowsThread_Function_Params    Make_Params2(WindowsThread_Num_Args, T, a) // T0 a0, T1 a1, T2 a2, ...
#define WindowsThread_Function_Args      Make_Params1(WindowsThread_Num_Args, a) // a0, a1, a2, ...

#undef WindowsThread_Comma

#if WindowsThread_Num_Args == 0
	#define WindowsThread_Comma
#else
	#define WindowsThread_Comma ,
#endif

namespace thread
{
	template <typename R WindowsThread_Comma WindowsThread_Template_Params>
	class WindowsThread<R (WindowsThread_Template_Args)>
	{
	public:
		typedef WindowsThread<R (WindowsThread_Template_Args)> self;
		typedef typename delegate::Delegate<R (WindowsThread_Function_Params)> run_delegate_type;
		typedef typename delegate::Delegate<void (self*)> notice_container_delegate_type;
		typedef typename delegate::Delegate<void (int32_t)> notice_user_delegate_type;
		// thread invoke content
		run_delegate_type			   run_delegate;
		// notice user thread invoke is end
		notice_user_delegate_type	   done_delegate;
		// notice containter thread invoke is end
		notice_container_delegate_type notice_container_delegate;
	public:
		WindowsThread()
			:handle_(NULL)
			,waitEvent_(NULL)
			,isStop_(false)
		{
		}
		~WindowsThread()
		{
			WaitForSingleObject(handle_,WAIT_FOR_STOPED_TIME);
			if (handle_ != NULL)
			{
				CloseHandle(handle_);
				handle_ = NULL;
			}
			if (waitEvent_ != NULL)
			{
				CloseHandle(waitEvent_);
				waitEvent_ = NULL;
			}
		}
		bool create()
		{
			if(NULL!=handle_)
			{
				return false;
			}
			waitEvent_ = CreateEvent(NULL,FALSE,FALSE,NULL);
			if(NULL==waitEvent_)
			{
				return false;
			}

#if defined(JELLY_WIN32)
			handle_ = (HANDLE)_beginthreadex(NULL,0,_threadProc,this,0,NULL);
#elif defined(JELLY_WINCE)
			handle_ = CreateThread(NULL, 0, _threadProc,this,0, NULL);
#endif
			return NULL!=handle_? true:false;
		}
		void start(WindowsThread_Function_Params)
		{
#if WindowsThread_Num_Args == 0
#else
			arguments_.copy(WindowsThread_Function_Args);
#endif
			SetEvent(waitEvent_);
		}
		void stop()
		{
			isStop_ = true;
			SetEvent(waitEvent_);
		}
	protected:
		WindowsThread( const self& );
		WindowsThread& operator = ( const self& );

#if defined(JELLY_WIN32)
		static unsigned int __stdcall _threadProc(void* param)
		{
			self* t = (self*)param;
			t->_actualThreadProc();
			_endthreadex(0);
			return 1;
		}
#elif defined(JELLY_WINCE)
		static unsigned long __stdcall _threadProc(void* param)
		{
			self* t = (self*)param;
			t->_actualThreadProc();
			return 1;
		}
#endif

		void _actualThreadProc()
		{
			while(!isStop_)
			{
				DWORD ret = WaitForSingleObject(waitEvent_,WAIT_FOR_RUN_INTERVAL);
				if (isStop_)
				{
					return;
				}
				if (WAIT_OBJECT_0 == ret)
				{
#if WindowsThread_Num_Args == 0
					run_delegate();
#elif WindowsThread_Num_Args == 1
					run_delegate(arguments_.a);
#elif WindowsThread_Num_Args == 2
					run_delegate(arguments_.a,arguments_.b);
#elif WindowsThread_Num_Args == 3
					run_delegate(arguments_.a,arguments_.b,arguments_.c);
#elif WindowsThread_Num_Args == 4
					run_delegate(arguments_.a,arguments_.b,arguments_.c,arguments_.d);
#elif WindowsThread_Num_Args == 5
					run_delegate(arguments_.a,arguments_.b,arguments_.c,arguments_.d,arguments_.e);
#elif WindowsThread_Num_Args == 6
					run_delegate(arguments_.a,arguments_.b,arguments_.c,arguments_.d,arguments_.e,arguments_.f);
#elif WindowsThread_Num_Args == 7
					run_delegate(arguments_.a,arguments_.b,arguments_.c,arguments_.d,arguments_.e,arguments_.f,arguments_.g);
#elif WindowsThread_Num_Args == 8
					run_delegate(arguments_.a,arguments_.b,arguments_.c,arguments_.d,arguments_.e,arguments_.f,arguments_.g,arguments_.h);
#endif

					run_delegate.clean();

					// notice and clear user
					done_delegate(run_end);
					done_delegate.clean();

					// for container
					notice_container_delegate(this);
				}
				else if (WAIT_TIMEOUT == ret)
				{
				}
			}
		}
	private:
		enum
		{
			init = 0,
			run_prepare,
			running,
			run_end, // run  end
			end,     // thread end
		};
	private:
		HANDLE handle_;
		HANDLE waitEvent_;
		bool isStop_;
#if WindowsThread_Num_Args == 0
#else
		tuple::Tuple<WindowsThread_Template_Args> arguments_;
#endif
	};
}
